package com.ttxs.fileformathandling.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ttxs.apiclientsdk.client.CwtApiClient;
import com.ttxs.apicommon.model.entity.User;
import com.ttxs.apicommon.model.entity.UserApiInfo;
import com.ttxs.fileformathandling.annotation.AuthCheck;
import com.ttxs.fileformathandling.common.BaseResponse;
import com.ttxs.fileformathandling.common.DeleteRequest;
import com.ttxs.fileformathandling.common.ErrorCode;
import com.ttxs.fileformathandling.common.ResultUtils;
import com.ttxs.fileformathandling.constant.CommonConstant;
import com.ttxs.fileformathandling.constant.UserConstant;
import com.ttxs.fileformathandling.exception.BusinessException;
import com.ttxs.fileformathandling.exception.ThrowUtils;
import com.ttxs.fileformathandling.mapper.UserDataStructureMapper;
import com.ttxs.fileformathandling.model.dto.userapiinfo.UserApiInfoAddRequest;
import com.ttxs.fileformathandling.model.dto.userapiinfo.UserApiInfoQueryRequest;
import com.ttxs.fileformathandling.model.dto.userapiinfo.UserApiInfoUpdateRequest;
import com.ttxs.fileformathandling.model.dto.userdatastructure.SimpleQuery;
import com.ttxs.fileformathandling.model.dto.userdatastructure.UserDataStructureAddRequest;
import com.ttxs.fileformathandling.model.dto.userdatastructure.UserDataStructureQueryRequest;
import com.ttxs.fileformathandling.model.dto.userdatastructure.UserDataStructureUpdateRequest;
import com.ttxs.fileformathandling.model.entity.UserDataStructure;
import com.ttxs.fileformathandling.service.UserApiInfoService;
import com.ttxs.fileformathandling.service.UserDataStructureService;
import com.ttxs.fileformathandling.service.UserService;
import com.ttxs.fileformathandling.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RPermitExpirableSemaphoreRx;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * user_api接口
 *
 * @author cwt
 */
@RestController
@RequestMapping("/user_data_structure")
@Slf4j
public class UserDataStructureController {

    @Resource
    private UserDataStructureService userDataStructureService;

    @Resource
    private UserDataStructureMapper userDataStructureMapper;

    @Resource
    private UserService userService;

    @Value("${upload.path}")
    private String savePath;

    @Value("${upload.address}")
    private String webAddress;

    private final List<String> fileSuffixList = Arrays.asList("csv", "json", "yml", "xml");

    // region 增删改查

    /**
     * 创建
     *
     * @param userDataStructureAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    public BaseResponse<Long> addUserDataStructure(UserDataStructureAddRequest userDataStructureAddRequest, HttpServletRequest request) {
        if (userDataStructureAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        UserDataStructure dataStructure = new UserDataStructure();
        BeanUtils.copyProperties(userDataStructureAddRequest, dataStructure);

        userDataStructureService.validUserDataStructure(dataStructure, true);
        User loginUser = userService.getLoginUser(request);
        dataStructure.setUserId(loginUser.getId());

        MultipartFile file = userDataStructureAddRequest.getFile();
        String path = savePath + "userDataStructure/" + loginUser.getId();
        String structureName = dataStructure.getStructureName();
        if (file != null) {
            String originalFilename = file.getOriginalFilename();
            assert originalFilename != null;
            int index = originalFilename.lastIndexOf(".") + 1;
            String fileSuffix = originalFilename.substring(index).toLowerCase();
            String filename = originalFilename.substring(0, index);

            if (!fileSuffixList.contains(fileSuffix)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "暂不支持除json、xml、csv、yaml类型的插件");
            }
            path = path + "/input/";
            File inDir = new File(path);
            if (!inDir.exists()) {
                if (!inDir.mkdirs()) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "文件目录创建失败");
                }
            }
            //保存文件
            File inFile = new File(inDir, originalFilename);
            try {
                file.transferTo(inFile); //转换文件
            } catch (IOException e) {
                e.printStackTrace();
            }

            path = savePath + "userDataStructure/" + loginUser.getId();
            String[] headers = null;
            if (dataStructure.getDataStructure() != null) {
                headers = dataStructure.getDataStructure().split(",");
            }

            headers = preDeal(path, filename, structureName, fileSuffix, headers, true, false);

            dataStructure.setDataStructure(String.join(",", headers));

            path = webAddress + webAddress + "/uploads/" + "userDataStructure/" + loginUser.getId() + "/output/" + structureName + ".csv";
            dataStructure.setDataUrl(path);
        } else {
            FileUtils.createFile(path + "/output/" + structureName + ".csv");
        }

        path = webAddress + webAddress + "/uploads/" + "userDataStructure/" + loginUser.getId() + "/output/" + structureName + ".csv";
        dataStructure.setDataUrl(path);

        boolean result = userDataStructureService.save(dataStructure);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        long newApiId = dataStructure.getId();
        return ResultUtils.success(newApiId);
    }

    private String[] preDeal(String path, String name, String structureName, String suffix, String[] headers, boolean append, boolean removeHead) {
        String inputPath = path + "/input/" + name + suffix;
        String outputPath = path + "/input/" + name + "csv";
        if ("json".equals(suffix)) {
            FileUtils.saveToFile(outputPath, JsonUtils.json2Csv(inputPath, ","), "UTF-8");
        } else if ("xml".equals(suffix)) {
            FileUtils.saveToFile(outputPath, XmlUtils.xml2Csv(inputPath), "UTF-8");
        } else if ("yaml".equals(suffix)) {
            FileUtils.saveToFile(outputPath, YamlUtils.yaml2Csv(inputPath), "UTF-8");
        } else if ("csv".equals(suffix)) {
            //csv文件不处理
        } else {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "暂不支持" + suffix + "类型的文件");
        }
        String resultPath = path + "/output/" + structureName + ".csv";
        FileUtils.createFile(resultPath);
        return CsvUtils.csvStandard(outputPath, resultPath, headers, append, removeHead);
    }

    /**
     * 删除
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteUserDataStructure(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User user = userService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断是否存在
        UserDataStructure oldDataStructure = userDataStructureService.getById(id);
        ThrowUtils.throwIf(oldDataStructure == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可删除
        if (!oldDataStructure.getUserId().equals(user.getId()) && userService.notAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean b = userDataStructureService.removeById(id);
        return ResultUtils.success(b);
    }

    /**
     * @param userDataStructureUpdateRequest
     * @return
     */
    @PostMapping("/update")
    public BaseResponse<Boolean> updateUserDataStructure(UserDataStructureUpdateRequest userDataStructureUpdateRequest, HttpServletRequest request) {
        if (userDataStructureUpdateRequest == null || userDataStructureUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);

        long id = userDataStructureUpdateRequest.getId();
        // 判断是否存在
        UserDataStructure oldUserDataStructure = userDataStructureService.getById(id);

        ThrowUtils.throwIf(oldUserDataStructure == null, ErrorCode.NOT_FOUND_ERROR);

        MultipartFile file = userDataStructureUpdateRequest.getFile();
        if (file != null) {
            String originalFilename = file.getOriginalFilename();
            assert originalFilename != null;
            int index = originalFilename.lastIndexOf(".") + 1;
            String fileSuffix = originalFilename.substring(index).toLowerCase();
            String filename = originalFilename.substring(0, index);
            //todo 转统一类型
            if (!fileSuffixList.contains(fileSuffix)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "暂不支持除json、xml、csv、yaml类型的插件");
            }
            String path = savePath + "userDataStructure/" + loginUser.getId() + "/input/";
            File inDir = new File(path);
            if (!inDir.exists()) {
                if (!inDir.mkdirs()) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "文件目录创建失败");
                }
            }
            //保存文件
            File inFile = new File(inDir, originalFilename);
            try {
                file.transferTo(inFile); //转换文件
            } catch (IOException e) {
                e.printStackTrace();
            }
            //判断文件架构是否一致，

            // 将内容合并
            path = savePath + "userDataStructure/" + loginUser.getId();
            String[] headers = oldUserDataStructure.getDataStructure().split(",");
            String structureName = oldUserDataStructure.getStructureName();
            preDeal(path, filename, structureName, fileSuffix, headers, userDataStructureUpdateRequest.isAppend(), userDataStructureUpdateRequest.isRemoveHead());

        }

        // 参数校验
        userDataStructureService.validUserDataStructure(oldUserDataStructure, false);

        boolean result = userDataStructureService.updateById(oldUserDataStructure);
        return ResultUtils.success(result);
    }

    @PostMapping("/query")
    public BaseResponse<String> simpleQuery(@RequestBody SimpleQuery simpleQuery, HttpServletRequest request) {
        String[] data = simpleQuery.getSql().split("\\s+");
        List<Integer> index = new ArrayList<>();
        String fields = data[1];
        String table = data[3]; //确定查询的结构
        QueryWrapper<UserDataStructure> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(table), "structureName", table);
        UserDataStructure dataStructure = userDataStructureMapper.selectOne(queryWrapper);
        if (dataStructure == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "该结构不存在");
        }
        //确定列
        int len = dataStructure.getDataStructure().split(",").length;
        if ("*".equals(fields)) {
            for (int i = 0; i < len; i++) {
                index.add(i);
            }
        } else {
            String[] field = data[1].split(",");
            for (String s : field) {
                try {
                    int i = Integer.parseInt(s);
                    if (i <= 0 || i > len) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "表中字段数不匹配");
                    }
                    index.add(i - 1);

                } catch (NumberFormatException e) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "between语句之间必须为数字");
                }
            }
        }
        //5 7

        int left;
        int right;
        if (data.length < 6) {
            left = 1;
            right = dataStructure.getDataStructure().split(",").length;
        } else {
            try {
                left = Integer.parseInt(data[5]);
                right = Integer.parseInt(data[7]);
            } catch (NumberFormatException e) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "between and之间应为数字");
            }
        }
        if (left > right || left < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "left >= 1 left <= right");
        }

        simpleQuery.setLeft(left);
        simpleQuery.setRight(right);
        simpleQuery.setIndex(index);
        String structureName = dataStructure.getStructureName();
        simpleQuery.setStructureName(structureName);
        User loginUser = userService.getLoginUser(request);
        String inputPath = savePath + "userDataStructure/" + loginUser.getId() + "/output/" + structureName + ".csv";
        File file = new File(inputPath);
        if (!file.exists()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "你未创建过该结构");
        }
        return ResultUtils.success(CsvUtils.csvQuery(simpleQuery, inputPath));

        //select * from table where between 1 and 2;
    }

    /**
     * 根据 id 获取
     *
     * @param id
     * @return
     */
    @GetMapping("/get")
    public BaseResponse<UserDataStructure> getUserDataStructureById(long id) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        UserDataStructure userDataStructure = userDataStructureService.getById(id);
        if (userDataStructure == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        return ResultUtils.success(userDataStructure);
    }

    /**
     * 分页获取列表（封装类）
     *
     * @param userDataStructureQueryRequest
     * @return
     */
    @PostMapping("/list")
    public BaseResponse<List<UserDataStructure>> listUserDataStructure(@RequestBody UserDataStructureQueryRequest userDataStructureQueryRequest) {
        UserDataStructure dataStructure = new UserDataStructure();
        if (userDataStructureQueryRequest != null) {
            BeanUtils.copyProperties(userDataStructureQueryRequest, dataStructure);
        }
        QueryWrapper<UserDataStructure> queryWrapper = new QueryWrapper<>(dataStructure);
        List<UserDataStructure> userDataStructureList = userDataStructureService.list(queryWrapper);
        return ResultUtils.success(userDataStructureList);
    }

    /**
     * 分页获取当前用户创建的资源列表
     *
     * @param userDataStructureQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page")
    public BaseResponse<Page<UserDataStructure>> listUserDataStructureByPage(@RequestBody UserDataStructureQueryRequest userDataStructureQueryRequest,
                                                                             HttpServletRequest request) {
        if (userDataStructureQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        UserDataStructure dataStructure = new UserDataStructure();
        BeanUtils.copyProperties(userDataStructureQueryRequest, dataStructure);
        String sortField = userDataStructureQueryRequest.getSortField();
        String sortOrder = userDataStructureQueryRequest.getSortOrder();
        long current = userDataStructureQueryRequest.getCurrent();
        long size = userDataStructureQueryRequest.getPageSize();

        // 限制爬虫
        ThrowUtils.throwIf(size > 50, ErrorCode.PARAMS_ERROR);
        QueryWrapper<UserDataStructure> queryWrapper = new QueryWrapper<>(dataStructure);
        queryWrapper.orderBy(StringUtils.isNotBlank(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC), sortField);
        Page<UserDataStructure> userDataStructurePage = userDataStructureService.page(new Page<>(current, size), queryWrapper);
        return ResultUtils.success(userDataStructurePage);
    }

}
